package com.example.office365wopi.service;

import com.example.office365wopi.exception.UnSupportedRequestException;
import com.example.office365wopi.request.WopiRequestHeader;
import com.example.office365wopi.response.CheckFileInfoResponse;
import com.example.office365wopi.rest.FileItem;
import com.example.office365wopi.rest.IdUrlMap;
import com.example.office365wopi.validator.WopiAuthenticationValidator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;

import static com.example.office365wopi.request.WopiRequestType.valueOf;

@Service
@Slf4j
public class WopiProtocalService {

    @Value("${localstorage.path}")
    private String filePath;

    private WopiAuthenticationValidator validator;
    private WopiLockService lockService;
    private IdUrlMap idUrlMap;

    @Autowired
    public WopiProtocalService(WopiAuthenticationValidator validator,
                               WopiLockService lockService, IdUrlMap idUrlMap) {
        this.validator = validator;
        this.lockService = lockService;
        this.idUrlMap = idUrlMap;
    }

    public ResponseEntity<Resource> handleGetFileRequest(String name, HttpServletRequest request) throws UnsupportedEncodingException, FileNotFoundException {
        log.info("调用下载={}", name);
        this.validator.validate(request);
        String path = filePath + name;
        File file = new File(path);
        HttpHeaders headers = new HttpHeaders();
        Resource resource = null;
        if (file.exists()) {
            resource = new InputStreamResource(new FileInputStream(file));
            headers.add("Content-Disposition", "attachment;filename=" +
                    new String(file.getName().getBytes("utf-8"), "ISO-8859-1"));
        } else {
            try {
                FileItem fileItem = idUrlMap.getUrl(name);
               log.info("download,fileItem={}",fileItem);
                resource = new UrlResource(fileItem.getUrl());
                if (resource.exists()) {
                    headers.add("Content-Disposition", "attachment;filename=" +
                            new String(fileItem.getFileName().getBytes("utf-8"), "ISO-8859-1"));
                }
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }

        }
        return ResponseEntity.ok()
                .headers(headers)
                .contentType(MediaType.parseMediaType("application/octet-stream"))
                .body(resource);
    }

    /**
     * @param name
     * @param content
     * @param request
     * @TODO: rework on it based on the description of document
     */
    public void handlePutFileRequest(String name, byte[] content, HttpServletRequest request) throws IOException {
        this.validator.validate(request);
        log.info("不支持修改");
     /*   Path path = Paths.get(filePath + name);
        Files.write(path, content);

      */
    }

    public ResponseEntity<CheckFileInfoResponse> handleCheckFileInfoRequest(String name, HttpServletRequest request) throws UnsupportedEncodingException {
        this.validator.validate(request);
        CheckFileInfoResponse info = new CheckFileInfoResponse();
        String fileName = URLDecoder.decode(name, "UTF-8");
        log.info("fileName={}", fileName);
        if (fileName != null && fileName.length() > 0) {
            File file = new File(filePath + fileName);
            if (file.exists()) {
                info.setBaseFileName(file.getName());
                info.setSize(file.length());
               // info.setOwnerId("admin");
                info.setVersion(file.lastModified());
                //暂时实现view
               /* info.setAllowExternalMarketplace(true);
                info.setUserCanWrite(true);
                info.setSupportsUpdate(true);
                info.setSupportsLocks(true);*/
            } else {
                try {
                    FileItem fileItem = idUrlMap.getUrl(name);
                    Resource resource = new UrlResource(fileItem.getUrl());
                    info.setBaseFileName(fileItem.getFileName());
                    info.setSize(resource.contentLength());
                  //  info.setOwnerId("admin");
                    info.setVersion(resource.lastModified());
                } catch (MalformedURLException e) {
                    throw new RuntimeException(e);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

       /* info.setAllowExternalMarketplace(false);
        info.setUserCanWrite(false);
        info.setSupportsUpdate(false);
        info.setSupportsLocks(false);*/
        log.info("CheckFileInfoResponse={}", info);
        return ResponseEntity.ok().contentType(MediaType.parseMediaType(MediaType.APPLICATION_JSON_UTF8_VALUE)).body(info);
    }

    public ResponseEntity handleEditFileRequest(String name, HttpServletRequest request) {
        this.validator.validate(request);

        logRequestParam(name, request);

        ResponseEntity responseEntity = ResponseEntity.ok().build();
        String requestType = request.getHeader(WopiRequestHeader.REQUEST_TYPE.getName());
        switch (valueOf(requestType)) {
            case PUT_RELATIVE_FILE:
                responseEntity = this.handlePutRelativeFileRequest(name, request);
                break;
            case LOCK:
               /* if (request.getHeader(WopiRequestHeader.OLD_LOCK.getName()) != null) {
                    responseEntity = this.lockService.handleUnlockAndRelockRequest(name, request);
                } else {
                    responseEntity = this.lockService.handleLockRequest(name, request);
                }*/
                break;
            case UNLOCK:
                //  responseEntity = this.lockService.handleUnLockRequest(name, request);
                break;
            case REFRESH_LOCK:
                // responseEntity = this.lockService.handleRefreshLockRequest(name, request);
                break;
            case UNLOCK_AND_RELOCK:
                //  responseEntity = this.lockService.handleUnlockAndRelockRequest(name, request);
                break;
            default:
                throw new UnSupportedRequestException("Operation not supported");
        }
        return responseEntity;
    }

    private void logRequestParam(String name, HttpServletRequest request) {
        System.out.println("name=" + name);
        Map<String, String[]> parameterMap = request.getParameterMap();
        for (Map.Entry<String, String[]> stringEntry : parameterMap.entrySet()) {

            String key = stringEntry.getKey();
            String[] values = stringEntry.getValue();
            System.out.println("key=" + key + ",values=" + Arrays.toString(values));
        }
        System.out.println("headers");

        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = headerNames.nextElement();
            System.out.println("head:" + key + "=" + request.getHeader(key));
        }
    }

    private ResponseEntity handlePutRelativeFileRequest(String name, HttpServletRequest request) {
        return null;
    }
}
